gitlab.com/SiaPrime/SiaPrime@v1.4.1/doc/Running and Writing Tests for SiaPrime.md (about) 1 # Running and Writing Tests for SiaPrime 2 Improving test coverage is a great way to start contributing to SiaPrime. 3 4 This guide focuses on how to write tests. You should also read 5 [doc/Developers.md][developers] to learn about SiaPrime code conventions and 6 quality standards. 7 8 9 #### Table of Contents 10 - [Running and Writing Tests for SiaPrime](#Running-and-Writing-Tests-for-SiaPrime) 11 - [Table of Contents](#Table-of-Contents) 12 - [Running tests for SiaPrime](#Running-tests-for-SiaPrime) 13 - [Updating code before testing](#Updating-code-before-testing) 14 - [Testing the entire build](#Testing-the-entire-build) 15 - [Testing a particular package or function](#Testing-a-particular-package-or-function) 16 - [Writing new tests for SiaPrime](#Writing-new-tests-for-SiaPrime) 17 - [A few guidelines](#A-few-guidelines) 18 - [Basic test format](#Basic-test-format) 19 - [Table-driven tests in Go](#Table-driven-tests-in-Go) 20 - [SiaPrimetest Package](#SiaPrimetest-Package) 21 - [Questions?](#Questions) 22 23 <a name="existing"></a> 24 ## Running tests for SiaPrime 25 Go's comprehensive [test package][pkg/testing] makes testing straightforward, 26 particularly when you use the bundled tools included in the 27 [SiaPrime makefile][makefile], including `make test`, `make cover`, `make bench`, 28 and their variants. 29 30 <a name="update"></a> 31 ### Updating code before testing 32 If you just want to run existing tests on the codebase as is, you just need to 33 pull the latest version of the original repo to your master branch. 34 35 ```bash 36 # Make sure you are in the right directory. 37 $ cd $GOPATH/src/github.com/<your Github username>/SiaPrime 38 # Also make sure you're working with the right branch. 39 $ git checkout master 40 # Pull latest changes from origin, the original SiaPrime repo. 41 $ git pull origin master 42 # Update your fork of the repo, which should be set up as a remote. 43 $ git push <remote> master 44 ``` 45 46 If you want to run tests on the new code you've added, first make sure the rest 47 of the code is up to date. New code should be on its own branch. 48 49 ```bash 50 # Make sure you are in the right directory. 51 $ cd $GOPATH/src/github.com/<your Github username>/SiaPrime 52 # Checkout the branch you made the changes on. 53 $ git checkout <branch name> 54 # Stash any tracked but uncommitted changes. 55 $ git stash 56 # Then switch back to `master` and update it to match the original repo. 57 $ git checkout master 58 $ git pull origin master 59 # Update your fork of the repo, which you should have set up as a remote. 60 $ git push <remote> master 61 # Make the updated `master` the new base of the branch you made the changes on, 62 # which involves reapplying all the commits made to that branch. Without the 63 # `--ignore-date` flag, git rebase changes the date on all the commits to the 64 # current date. 65 $ git checkout <branch name> 66 $ git rebase master --ignore-date 67 # Restore the changes you stashed earlier. 68 $ git stash pop 69 ``` 70 When you call `rebase`, you may run into some merge conflicts. Luke Champine's 71 ['How to into git and GitHub'][luke] has more details (and many useful tricks). 72 73 Once the branch you want to test is up to date, you're ready to run some tests. 74 75 <a name="entire"></a> 76 ### Testing the entire build 77 The `make test` command runs all tests (functions starting with `Test` in 78 `_test.go` files) for each package, setting off a panic for any test that runs 79 longer than 5s. For verbose output, run `make test-v` (which panics after 15s 80 instead of 5s). Finally, `make test-long` has verbose output, only panics when 81 a test takes 5 minutes, and also cleans up your code using `gofmt` and `golint`. 82 **You should run** `make test-long` **before each pull request.** 83 84 Run `make cover` to run all tests for each package and generate color-coded 85 .html visualizations of test coverage by function for each source file. Open 86 `cover/<module>.html` in a browser to inspect a module's test coverage. For 87 example, here's part of the html file generated for the persist package: 88 89 ![Screenshot](assets/covertool.png) 90 91 Meanwhile, `make bench` will call `gofmt` on all packages, then run all 92 benchmarks (functions starting with `Benchmark` in `_test.go` files). 93 94 <a name="particular"></a> 95 ### Testing a particular package or function 96 To run tests for just a certain package, run `make test pkgs=./<package>`. To run 97 a certain test function, run `make test pkgs=./<package> run=<function>`. The same 98 goes for `make test-long`, `make cover` and `make bench`. 99 100 For example, running `test-long` on the package persist produces this output: 101 102 ```bash 103 $ make test-long pkgs=./persist 104 rm -rf release doc/whitepaper.aux doc/whitepaper.log doc/whitepaper.pdf 105 gofmt -s -l -w ./persist 106 go install ./persist 107 go vet ./persist 108 go test -v -race -tags='testing debug' -timeout=300s ./persist -run=Test 109 === RUN TestOpenDatabase 110 --- PASS: TestOpenDatabase (0.42s) 111 === RUN TestSaveLoad 112 --- PASS: TestSaveLoad (0.00s) 113 === RUN TestSaveLoadFile 114 --- PASS: TestSaveLoadFile (0.01s) 115 === RUN TestSaveLoadFileSync 116 --- PASS: TestSaveLoadFileSync (0.00s) 117 === RUN TestLogger 118 --- PASS: TestLogger (0.00s) 119 === RUN TestLoggerCritical 120 --- PASS: TestLoggerCritical (0.00s) 121 === RUN TestIntegrationRandomSuffix 122 --- PASS: TestIntegrationRandomSuffix (0.01s) 123 === RUN TestAbsolutePathSafeFile 124 --- PASS: TestAbsolutePathSafeFile (0.00s) 125 === RUN TestRelativePathSafeFile 126 --- PASS: TestRelativePathSafeFile (0.00s) 127 PASS 128 ok gitlab.com/SiaPrime/SiaPrime/persist 1.485s 129 $ 130 ``` 131 132 <a name="write"></a> 133 ## Writing new tests for SiaPrime 134 When you run `make cover`, you'll notice that many files have pretty low 135 coverage. We're working on fixing that, but we could use your help. 136 137 <a name="naming"></a> 138 ### A few guidelines 139 * The test functions for `filename.go` should go in `filename_test.go` in the 140 same directory and package. 141 * A test function name should start with `Test` and clearly convey what is 142 being tested. 143 * You should declare function-specific variables and constants locally (inside 144 the test function) instead of globally (outside the test function). [That 145 holds in general][global], not just for tests. 146 * As always, code should adhere to the standards and conventions laid out in 147 [doc/Developers.md][developers]. 148 * If a test interacts with the disk it should be skipped during the short tests 149 by including the following at the beginning of the test: 150 ```go 151 if testing.Short() { 152 t.SkipNow() 153 } 154 ``` 155 156 <a name="basic"></a> 157 ### Basic test format 158 Suppose we'd like to test the Bar method belonging to type Foo. 159 160 ```go 161 // TestFoo checks that the Bar method on type Foo responds correctly to a normal 162 // input and returns the expected error when given a bad input. 163 func TestFoo(t *testing.T) { 164 foo, err := NewFoo() 165 if err != nil { 166 // If NewFoo failed, we can't continue testing. 167 t.Fatal(err) 168 } 169 170 // Try a normal input; should succeed. 171 err := foo.Bar(3) 172 if err != nil { 173 // Report the error, but don't abort the test. 174 t.Error(err) 175 } 176 177 // Try a bad input; should return an error. 178 // NOTE: Always prefer to compare to a specific error, rather than 179 // err == nil 180 err = Foo.Bar(0) 181 if err != errDivideByZero { 182 t.Errorf("expected errDivideByZero, got %v", err) 183 } 184 } 185 186 ``` 187 188 <a name="table"></a> 189 ### Table-driven tests in Go 190 If you're looking to test a bunch of inputs, write a [table-driven test][table] 191 with a slice of anonymous structs. For example, see `TestParseFileSize` in 192 [spc/parse_test.go][parse_test]: 193 194 ```go 195 func TestParseFilesize(t *testing.T) { 196 // Define a table of test cases in the form of a slice of anonymous structs. 197 tests := []struct { 198 in, out string 199 err error 200 }{ 201 {"1b", "1", nil}, 202 {"1KB", "1000", nil}, 203 {"1MB", "1000000", nil}, 204 {"1GB", "1000000000", nil}, 205 {"1TB", "1000000000000", nil}, 206 {"1KiB", "1024", nil}, 207 {"1MiB", "1048576", nil}, 208 {"1GiB", "1073741824", nil}, 209 {"1TiB", "1099511627776", nil}, 210 {"", "", errUnableToParseSize}, 211 {"123", "123", nil}, 212 {"123TB", "123000000000000", nil}, 213 {"123GiB", "132070244352", nil}, 214 {"123BiB", "", errUnableToParseSize}, 215 {"GB", "", errUnableToParseSize}, 216 {"123G", "", errUnableToParseSize}, 217 {"123B99", "", errUnableToParseSize}, 218 {"12A3456", "", errUnableToParseSize}, 219 {"1.23KB", "1230", nil}, 220 {"1.234KB", "1234", nil}, 221 {"1.2345KB", "1234", nil}, 222 } 223 // Loop through the table of test cases to make sure ParseFileSize returns 224 // the expected output and error for each. 225 for _, test := range tests { 226 res, err := parseFilesize(test.in) 227 if res != test.out || err != test.err { 228 t.Errorf("parseFilesize(%v): expected %v %v, got %v %v", test.in, test.out, test.err, res, err) 229 } 230 } 231 } 232 ``` 233 234 <a name="siaPrimetest"> 235 ### SiaPrimetest Package 236 When deciding what tests to write for SiaPrime, you should consider whether the 237 best test is a unit test or a siaprimetest. Ideally both a unit test and a 238 siaprimetest is written for new code. A unit test should explicitly test the new 239 code functionality and a siaprimetest should test the integration of the code 240 and how itaffects the rest of the platform. All the tests in the siaprimetest 241 package should use the API to execute the test. The idea is that everything that 242 is trying to be tested should be able to be controlled and verified through the 243 API. If you are looking for a place to start, there are many examples of older 244 tests that could be upgraded to siaprimetests. 245 246 <a name="questions"></a> 247 ## Questions? 248 Read these if you haven't already: 249 * getting started with Go 250 * SiaPrime, and git 251 * [doc/Developers.md][developers]: conventions and quality standards for 252 * SiaPrime code 253 254 Some other useful resources, some of which have been linked to already: 255 * [Golang.org page on the go testing package][pkg/testing] 256 * [Writing Table-Driven Tests in Go][table] 257 * [How to Write Benchmarks in Go][cheney-benchmarks] 258 * [How to into git and GitHub][luke]: an essential introduction to git 259 260 And feel free to ask questions on the [#development channel][discord] on the 261 SiaPrime Discord. 262 Odds are, someone else is wondering the same thing. 263 264 [pkg/testing]: https://golang.org/pkg/testing/ 265 [makefile]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/Makefile 266 [luke]: https://gist.github.com/lukechampine/6418449 267 [developers]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/doc/Developers.md 268 [table]: http://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go 269 [boltdb_test.go]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/persist/boltdb_test.go 270 [cheney-benchmarks]: http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go 271 [pkg/testing]: https://golang.org/pkg/testing/ 272 [discord]: https://discord.gg/5DAgTn8 273 [parse_test]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/spc/parse_test.go 274 [global]: http://c2.com/cgi/wiki?GlobalVariablesAreBad